package il.ac.technion.wiki.impl.tests;

import il.ac.technion.wiki.api.IDataStore;
import il.ac.technion.wiki.api.IWikiEngine.IWikiContent;
import il.ac.technion.wiki.api.IDataStore.DataStoreException;
import il.ac.technion.wiki.api.IDataStore.NameExistsException;
import il.ac.technion.wiki.api.IDataStore.NotFoundException;
import il.ac.technion.wiki.api.search.AndSearchExpression;
import il.ac.technion.wiki.api.search.ISearchExpression;
import il.ac.technion.wiki.api.search.NotSearchExpression;
import il.ac.technion.wiki.api.search.OrSearchExpression;
import il.ac.technion.wiki.api.search.TextSearchExpression;
import il.ac.technion.wiki.impl.storage.SimpleDataStorage;

import org.junit.Test;

import junit.framework.TestCase;

public class TestDataStore extends TestCase{
	@Test
	public void testFunctunality1() throws NotFoundException, NameExistsException, DataStoreException{
		IDataStore ds = new SimpleDataStorage();
		ds.setContentClass(WikiContentStub.class);
		String[] words = {"the", "and", "is", ".", ",", "?", "!", "(", ")", "\"", "\'", "-", ":"}; 
		ds.setNeutralWords(words);
				
		testBadPut(ds, getWikiContent("A", "new york 0", 0), false, NotFoundException.class);
		testBadPut(ds, getWikiContent("B", "new york 0", 0), false, NotFoundException.class);
		testBadPut(ds, getWikiContent("C", "new york 0", 0), false, NotFoundException.class);
		testBadPut(ds, getWikiContent("A", "new york 0", -1), true, DataStoreException.class);
		ds.put(getWikiContent("A", "new york 0", 0), true);
		testBadPut(ds, getWikiContent("A", "new york 0", 0), true, NameExistsException.class);
		ds.put(getWikiContent("A", "new york 1", 1), false);
		ds.put(getWikiContent("A", "new york 2", 2), false);
		ds.put(getWikiContent("A", "new york 3", 3), false);
		ds.put(getWikiContent("A", "new york 4", 4), false);
		ds.put(getWikiContent("A", "new york 5", 5), false);
		ds.put(getWikiContent("A", "new york 6", 6), false);
		ds.put(getWikiContent("A", "new york 7", 7), false);
		ds.put(getWikiContent("A", "new york 8", 8), false);
		
		testBadGet(ds, "A", 20, DataStoreException.class);
		testBadGet(ds, "B", 0, NotFoundException.class);
		testBadGet(ds, "A", -1, DataStoreException.class);
		assertEquals("new york 8", ds.get("A", 8).getText());		
		assertEquals("new york 6", ds.get("A", 6).getText());
		assertEquals("new york 5", ds.get("A", 5).getText());
		
		
		ds.put(getWikiContent("A", "new york 6", 6), false);
		testBadGet(ds, "A", 8, DataStoreException.class);
		testBadGet(ds, "A", 7, DataStoreException.class);
		ds.put(getWikiContent("A", "new york 5", 5), false);
		testBadGet(ds, "A", 6, DataStoreException.class);
		
		assertEquals("new york 0", ds.get("A", 0).getText());		
		assertEquals("new york 1", ds.get("A", 1).getText());
		assertEquals("new york 2", ds.get("A", 2).getText());
		assertEquals("new york 3", ds.get("A", 3).getText());		
		assertEquals("new york 4", ds.get("A", 4).getText());
		assertEquals("new york 5", ds.get("A", 5).getText());
		
		
		ds.put(getWikiContent("B", "new york new york", 0), true);
		ds.rename("A", "A1");
		ds.rename("A1", "A");
		ds.rename("A", "A1");
		testBadRename(ds, "A", "C", NotFoundException.class);
		testBadRename(ds, "A1", "B", NameExistsException.class);
		ds.rename("A1", "A2");
		testBadRename(ds, "A1", "C", NotFoundException.class);
		testBadRename(ds, "B", "A2", NameExistsException.class);
		ds.rename("A2", "A");
		
		
		
		ds.put(getWikiContent("B", "B", 1), false);
		ds.put(getWikiContent("C", "C", 0), true);
		ds.put(getWikiContent("D", "D", 0), true);
		ds.put(getWikiContent("E", "E", 0), true);
		ds.put(getWikiContent("F", "F", 0), true);
		ds.put(getWikiContent("G", "G", 0), true);
		
		testBadDelete(ds, "A1", NotFoundException.class);
		testBadDelete(ds, "A2", NotFoundException.class);
		testBadDelete(ds, "A3", NotFoundException.class);
		ds.delete("A");
		testBadGet(ds, "A", 0, NotFoundException.class);
		testBadDelete(ds, "A", NotFoundException.class);
		ds.delete("B");
		testBadGet(ds, "B", 0, NotFoundException.class);
		testBadDelete(ds, "B", NotFoundException.class);
		ds.delete("C");
		testBadGet(ds, "C", 0, NotFoundException.class);
		testBadDelete(ds, "C", NotFoundException.class);
		ds.delete("D");
		testBadGet(ds, "D", 0, NotFoundException.class);
		testBadDelete(ds, "D", NotFoundException.class);
	}
	
	void testBadGet(IDataStore ds, String name, int revision, Class<? extends Exception> exceptionClass){
		try {
			ds.get(name, revision);
			assertFalse(true);
		}catch (Exception e){
			assertEquals(e.getClass(), exceptionClass);
		}
	}
	
	void testBadPut(IDataStore ds, IWikiContent wc, boolean insert, Class<? extends Exception> exceptionClass){
		try {
			ds.put(wc, insert);
			assertFalse(true);
		}catch (Exception e){
			assertEquals(e.getClass(), exceptionClass);
		}
	}
	
	void testBadRename(IDataStore ds, String name, String newName, Class<? extends Exception> exceptionClass){
		try {
			ds.rename(name, newName);
			assertFalse(true);
		}catch (Exception e){
			assertEquals(e.getClass(), exceptionClass);
		}
	}
	
	
	void testBadDelete(IDataStore ds, String name, Class<? extends Exception> exceptionClass){
		try {
			ds.delete(name);
			assertFalse(true);
		}catch (Exception e){
			assertEquals(e.getClass(), exceptionClass);
		}
	}
	IWikiContent getWikiContent(String name, String text, int revision){
		return new WikiContentStub(name, text, revision);
	}
	@Test
	public void testSearch() throws NotFoundException, NameExistsException, DataStoreException{
		SimpleDataStorage ds = new SimpleDataStorage();
		ds.setContentClass(WikiContentStub.class);
		String[] words = {"the", "and", "is", ".", ",", "?", "!", "(", ")", "\"", "\'", "-", ":", "\t", "\n"}; 
		ds.setNeutralWords(words);
				
		ds.put(getWikiContent("A", "new york 0", 0), true);
		ds.put(getWikiContent("A", "new york 1", 1), false);
		ds.put(getWikiContent("A", "new york 2", 2), false);
		ds.put(getWikiContent("A", "new york 3", 3), false);
		ds.put(getWikiContent("A", "new york 4", 4), false);
		ds.put(getWikiContent("A", "new york 5", 5), false);
		ds.put(getWikiContent("A", "new york 6", 6), false);
		ds.put(getWikiContent("A", "new york 7", 7), false);
		ds.put(getWikiContent("A", "new york 8", 8), false);
		ds.put(getWikiContent("B", "New Yor----", 0), true);
		ds.put(getWikiContent("B", "New York, New York", 1), false);
		ds.put(getWikiContent("C", "Haifa, Tel Aviv", 0), true);
		ds.put(getWikiContent("D", "NeW!.......and			\n\n\n---------\n\n\n YoRk, sgdfgsdfg  			", 0), true);
		ds.put(getWikiContent("E", "the white, the blue,....( and the red )", 0), true);
		ds.put(getWikiContent("F", "red blue", 0), true);
		ds.put(getWikiContent("G", "blue red", 0), true);
		{
			IWikiContent[] expected = {getWikiContent("A", "new york 8", 8), getWikiContent("B", "New York, New York", 1), getWikiContent("D", "NeW!.......and			\n\n\n---------\n\n\nYoRk, sgdfgsdfg  			", 0)};
			IWikiContent[] actual = ds.search(new TextSearchExpression("new york"), 0);
			assertSearchResults(expected, actual);
		}
		{
			IWikiContent[] expected = {getWikiContent("E", "the white, the blue,....( and the red )", 0), getWikiContent("G", "blue red", 0)};
			IWikiContent[] actual = ds.search(new TextSearchExpression("blue red"), 0);
			assertSearchResults(expected, actual);
		}
	}
	
	@Test
	public void testSearch2() throws NotFoundException, NameExistsException, DataStoreException{	
		SimpleDataStorage ds = new SimpleDataStorage();
		ds.setContentClass(WikiContentStub.class);
		String[] words = {"the", "and", "is", ".", ",", "?", "!", "(", ")", "\"", "\'", "-", ":", "\t", "\n"}; 
		ds.setNeutralWords(words);
		
		IWikiContent[] contents = {getWikiContent("A", "0 00 TTTTT TTTTT new york 0", 0), 
				getWikiContent("B", "TTTT New Yor---- 00000 00 NEW", 0), 
				getWikiContent("C", "Haifa, Tel Aviv, 0000", 0), 
				getWikiContent("D", "NeW!.......and			\n\n\n---------\n\n\n YoRk, TTTT, sgdfgsdfg  			TTTT TTTT TTTT", 0), 
				getWikiContent("E", "TTTT new york new york new york new york new york new york", 0), 
				getWikiContent("F", "the white, the blue,....( and the red )", 0), 
				getWikiContent("G", "red blue ne w", 0), 
				getWikiContent("H", "blue red", 0),
				getWikiContent("J", "blue n  ew nen w new new new red", 0)};
		for (IWikiContent content: contents)
			ds.put(content, true);
		
		// Query = ((("new york") and ("TTTT")) or ("0")) or (not ("new"))
		ISearchExpression expr = new OrSearchExpression(new OrSearchExpression(new AndSearchExpression(new TextSearchExpression("new york"), new TextSearchExpression("TTTT")), new TextSearchExpression("0")), new NotSearchExpression(new TextSearchExpression("new")));
		IWikiContent[] expected = {contents[0], contents[1], contents[2], contents[5], contents[6], contents[7]};
		IWikiContent[] actual = ds.search(expr, 5000);
		assertSearchResults(expected, actual);
	}	
	
	
	void assertSearchResults(IWikiContent[] expected, IWikiContent[] actual){
		for (IWikiContent wc1: expected){
			boolean found = false;
			for (IWikiContent wc2: actual){
				if (wc1.getName() ==  wc2.getName() && wc1.getRevision() ==  wc2.getRevision()){
					found = true;
					break;
				}
				
			}
			if (found == false){
				StringBuffer sb = new StringBuffer();
				sb.append("<");
				for (IWikiContent wc2: actual){
					sb.append(" (" + wc2.getName()+", " + wc2.getRevision() + ")," );					
				}
				sb.append(">");
				assertFalse(wc1.getName() + ", " + wc1.getRevision() + " was not found in actual:" + sb.toString(),true);
			}
		}
		for (IWikiContent wc1: actual){
			boolean found = false;
			for (IWikiContent wc2: expected){
				if (wc1.getName() ==  wc2.getName() && wc1.getRevision() ==  wc2.getRevision()){
					found = true;
					break;
				}
				
			}
			if (found == false){
				StringBuffer sb = new StringBuffer();
				sb.append("<");
				for (IWikiContent wc2: expected){
					sb.append(" (" + wc2.getName()+", " + wc2.getRevision() + ")," );					
				}
				sb.append(">");
				assertFalse(wc1.getName() + ", " + wc1.getRevision() + " was not found in expected:" + sb.toString(),true);
			}
		}
	}
}
